﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using SSLLib;

namespace ManagedClient
{
	class Program
	{
		static void Send(Socket s, byte[] data)
		{
			s.Send(data, 0, data.Length, SocketFlags.None);
		}

		static byte[] Read(Socket s)
		{
			const int MAX_BUF_SIZE = 16384;
			byte[] buffer = new byte[MAX_BUF_SIZE];
			int len = s.Receive(buffer, MAX_BUF_SIZE, SocketFlags.None);
			byte[] outbuf = new byte[len];
			Buffer.BlockCopy(buffer, 0, outbuf, 0, len);
			return outbuf;
		}

		static void Main(string[] args)
		{
            using (var sslt = new SSLLib.SSLTransport())
            {
				String host = "pop.gmail.com";
				IPHostEntry iphostentry = Dns.GetHostEntry(host);
				IPEndPoint ipendpoint = new IPEndPoint(iphostentry.AddressList[0], 995);
				Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
				s.Connect(ipendpoint);
				byte[] extradata;
				sslt.Handshake(
					host, 
					(byte[] data) => Send(s, data),
					() => Read(s),
					out extradata);

				//
				//	Get response from the socket
				//
				byte[] response = Read(s);
				if (extradata != null) // add extra stuff from previous round of decryption
				{
					var concat = new byte[response.Length + extradata.Length];
					extradata.CopyTo(concat, 0);
					response.CopyTo(concat, extradata.Length);
					response = concat;
				}

				var decryptedResponse = new StringBuilder();
				sslt.Decrypt(
					response,
					(byte[] data) => Send(s, data),
					(byte[] data) => decryptedResponse.Append(ASCIIEncoding.ASCII.GetChars(data))
				);

				Console.WriteLine("Received " + decryptedResponse);

				byte[] encryptedMessage =
					sslt.Encrypt(
						ASCIIEncoding.ASCII.GetBytes("USER abc@def.com\r\n"));

				Send(s, encryptedMessage);

				response = Read(s);

				decryptedResponse = new StringBuilder();
				sslt.Decrypt(
					response,
					(byte[] data) => Send(s, data),
					(byte[] data) => decryptedResponse.Append(ASCIIEncoding.ASCII.GetChars(data))
				);

				Console.WriteLine("Received " + decryptedResponse);

				sslt.Done();
            }
            Console.WriteLine("Done!");
		}
	}
}
